home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 4 / QRZ Ham Radio Callsign Database - Volume 4.iso / files / tcpip / amiga / rhinosrc.lha / view.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-17  |  7.1 KB  |  333 lines

  1. #include <stdio.h>
  2. #include "global.h"
  3. #include "session.h"
  4. #include "tty.h"
  5. #include "commands.h"
  6. #include "socket.h"
  7.  
  8. /*#include <dos.h>*/
  9.  
  10. static long lineseek __ARGS((FILE *fp,long offset,int nlines,int width));
  11. static int ctlproc __ARGS((int c));
  12.  
  13. #define    ESC    27
  14. #define    CTLD    4
  15. #define    CTLU    21
  16. #define    FF    CTLL
  17. #define    CTLL    12
  18. #define    CTLN    14
  19. #define    CTLP    16
  20. #define    CTLV    22
  21.  
  22. int
  23. doview(argc,argv,p)
  24. int argc;
  25. char *argv[];
  26. void *p;
  27. {
  28.     FILE *fp;
  29.  
  30.     if((fp = fopen(argv[1],READ_TEXT)) == NULLFILE){
  31.         printf("Can't read %s\n",argv[1]);
  32.         return 1;
  33.     }
  34.     newproc("view",512,view,0,(void *)fp,NULL,0);
  35.     return 0;    
  36. }
  37. /* Random-access file display program. Used both to read local
  38.  * files with the "view" command, and by the FTP client to view
  39.  * directory listings, temporary copies of read files, etc.
  40.  *
  41.  */
  42. void
  43. view(s,p1,p2)
  44. int s;        /* If non-zero, poll interval for a changing file */
  45. void *p1;    /* Open file pointer to read from */
  46. void *p2;    /* If non-null, name to give to session. We free it */
  47. {
  48.     struct session *sp;
  49.     FILE *fp;
  50.     char *name;
  51.     int c;
  52.     long offset = 0;
  53.     int row,col;
  54.     int cols = 80;
  55.     int rows = 25;
  56.     int32 polldelay = 0;
  57.  
  58.     fp = (FILE *)p1;
  59.     if(p2 != NULL)
  60.         name = (char *)p2;
  61.     else
  62.         name = fpname(fp);
  63.  
  64.     if((sp = newsession(name,VIEW,1)) == NULLSESSION)
  65.         return;
  66.  
  67.     if(p2 != NULL)
  68.         free(name);
  69.  
  70.     if(s != 0)
  71.         polldelay = s;
  72.     sp->ctlproc = ctlproc;
  73.     /* Put tty into raw mode so single-char responses will work */
  74.     sp->ttystate.echo = sp->ttystate.edit = 0;
  75.     for(;;){
  76.         fseek(fp,offset,SEEK_SET);
  77.         putchar(FF);    /* Clear screen */
  78. #ifdef AMIGA
  79.         getdisplayrowscols(stdout->ptr, &rows, &cols);
  80. #endif
  81.         /* Display a screen's worth of data, keeping track of
  82.          * cursor location so we know when the screen is full
  83.          */
  84.         col = row = 0;
  85.         while((c = getc(fp)),c != EOF){
  86.             switch(c){
  87.             case '\n':
  88.                 row++;
  89.                 col = 0;
  90.                 break;
  91.             case '\t':
  92.                 if(col < cols - 8)
  93.                     col = (col + 8) & ~7;
  94.                 break;
  95.             default:
  96.                 col++;
  97.                 break;
  98.             }
  99.             if(col >= cols){
  100.                 /* Virtual newline caused by wraparound */
  101.                 col = 0;
  102.                 row++;
  103.             }
  104.             if(row >= rows)
  105.                 break;    /* Screen now full */
  106.             putchar(c);
  107.         }
  108. #ifdef    notdef
  109.         if(feof(fp) && offset != 0){
  110.             /* Hit end of file. Back up proper number of
  111.              * lines and try again.
  112.              */
  113.             offset = lineseek(fp,offset,row-rows,cols);
  114.             continue;
  115.         }
  116. #endif
  117.         fflush(stdout);
  118.         /* If we hit the end of the file and the file may be
  119.          * growing, then set an alarm to time out the getchar()
  120.          */
  121.         do {
  122.             if(feof(fp) && polldelay != 0){
  123.                 alarm(polldelay);
  124.             }
  125.             c = getchar();    /* Wait for user keystroke */
  126.             alarm(0L);    /* Cancel alarm */
  127.             if(c != -1 || errno != EALARM)
  128.                 break;    /* User hit key */
  129.             /* Alarm timeout; see if more data arrived by
  130.              * clearing the EOF flag, trying to read
  131.              * another byte, and then testing EOF again
  132.              */
  133.             clearerr(fp);
  134.             (void)getc(fp);
  135.             c = '`';    /* Simulate a no-op keypress */
  136.         } while(feof(fp));
  137.         switch(c){
  138.         case 'h':    /* Home */
  139.         case 'H':
  140.         case '<':    /* For emacs users */
  141.             offset = 0;
  142.             break;
  143.         case 'e':    /* End */
  144.         case '>':    /* For emacs users */
  145.             fseek(fp,0L,SEEK_END);
  146.             offset = lineseek(fp,ftell(fp),-rows,cols);
  147.             break;
  148.         case CTLD:    /* Down one half screen (for VI users) */
  149.             if(!feof(fp))
  150.                 offset = lineseek(fp,offset,rows/2,cols);
  151.             break;
  152.         case CTLU:    /* Up one half screen (for VI users) */
  153.             offset = lineseek(fp,offset,-rows/2,cols);
  154.             break;
  155.         case 'd':    /* down line */
  156.         case CTLN:    /* For emacs users */
  157.         case 'j':    /* For vi users */
  158.         case '\r':    /* For more users */
  159.         case '\n':    /* For more users */
  160.             if(!feof(fp))
  161.                 offset = lineseek(fp,offset,1,cols);
  162.             break;
  163.         case 'D':    /* Down page */
  164.         case CTLV:    /* For emacs users */
  165.         case ' ':    /* For more users */
  166.             if(!feof(fp))
  167.                 offset = lineseek(fp,offset,rows,cols);
  168.             break;
  169.         case 'u':    /* up line */
  170.         case CTLP:    /* for emacs users */
  171.         case 'k':    /* for vi users */
  172.             offset = lineseek(fp,offset,-1,cols);
  173.             break;
  174.         case 'U':    /* Up page */
  175.         case 'v':    /* for emacs users */
  176.         case '\b':    /* for less users */
  177.         case '\177':    /* for less users */
  178.             offset = lineseek(fp,offset,-rows,cols);
  179.             break;
  180.         case 'q':
  181.         case 'Q':
  182.         case ESC:
  183.             goto done;
  184.         default:
  185.             break;    /* Redisplay screen */
  186.         }
  187.     }
  188. done:    fclose(fp);
  189.     freesession(sp);
  190. }
  191. /* Given a starting offset into an open file stream, scan forwards
  192.  * or backwards the specified number of lines and return a pointer to the
  193.  * new offset.
  194.  */
  195. static long
  196. lineseek(fp,start,nlines,width)
  197. FILE *fp;    /* Open file stream */
  198. long start;    /* Offset to start searching backwards from */
  199. int nlines;    /* Number of lines to move forward (+) or back (-) */
  200. int width;    /* Screen width (max line size) */
  201. {
  202.     long offset;
  203.     long *pointers;
  204.     int col = 0;
  205.     int c;
  206.     int newlines = 0;
  207.  
  208.     if(nlines == 0)
  209.         return start;    /* Nothing to do */
  210.  
  211.     if(nlines > 0){        /* Look forward requested # of lines */
  212.         fseek(fp,start,SEEK_SET);
  213.         col = 0;
  214.         while((c = getc(fp)),c != EOF){
  215.             switch(c){
  216.             case '\n':
  217.                 newlines++;
  218.                 col = 0;
  219.                 break;
  220.             case '\t':
  221.                 if(col < width - 8)
  222.                     col = (col + 8) & ~7;
  223.                 break;
  224.             default:
  225.                 col++;
  226.                 break;
  227.             }
  228.             if(col >= width){
  229.                 /* Virtual newline caused by wraparound */
  230.                 col = 0;
  231.                 newlines++;
  232.             }
  233.             if(newlines >= nlines)
  234.                 break;    /* Found requested count */
  235.         }
  236.         return ftell(fp);    /* Could be EOF */
  237.     }
  238.     /* Backwards scan (the hardest)
  239.      * Start back up at most (width + 2) chars/line from the start.
  240.      * This handles full lines followed by expanded newline
  241.      * sequences
  242.      */
  243.     nlines = -nlines;
  244.     offset = (width + 2)*(nlines + 1);
  245.     if(offset > start)
  246.         offset = 0;    /* Go to the start of the file */
  247.     else
  248.         offset = start - offset;
  249.     fseek(fp,offset,SEEK_SET);
  250.  
  251.     /* Keep a circular list of the last 'nlines' worth of offsets to
  252.      * each line, starting with the first
  253.      */
  254.     pointers = (int32 *)calloc(sizeof(long),nlines);
  255.     pointers[newlines++ % nlines] = offset;
  256.  
  257.     /* Now count newlines up but not including the original
  258.      * starting point
  259.      */
  260.     col = 0;
  261.     for(;;){
  262.         c = getc(fp);
  263.         switch(c){
  264.         case EOF:
  265.             goto done;
  266.         case '\n':
  267.             col = 0;
  268.             offset = ftell(fp);
  269.             if(offset >= start)
  270.                 goto done;
  271.             pointers[newlines++ % nlines] = offset;
  272.             break;
  273.         case '\t':
  274.             if(col < width - 8)
  275.                 col = (col + 8) & ~7;
  276.             break;
  277.         default:
  278.             col++;
  279.             break;
  280.         }
  281.         if(col >= width){
  282.             /* Virtual newline caused by wraparound */
  283.             col = 0;
  284.             offset = ftell(fp);
  285.             if(offset >= start)
  286.                 goto done;
  287.             pointers[newlines++ % nlines] = offset;
  288.         }
  289.     }
  290.     done:;
  291.     if(newlines >= nlines){
  292.         /* Select offset pointer nlines back */
  293.         offset = pointers[newlines % nlines];
  294.     } else {
  295.         /* The specified number of newlines wasn't seen, so
  296.          * go to the start of the file
  297.          */
  298.         offset = 0;
  299.     }
  300.     free(pointers);
  301.     return offset;
  302. }
  303.  
  304. /* Handle special keystrokes */
  305. static int
  306. ctlproc(c)
  307. int c;
  308. {
  309.     switch(c){
  310.     case 256 + 71:    /* HOME */
  311.         putc('h',Current->input);
  312.         break;
  313.     case 256 + 72:    /* Cursor up */
  314.         putc('u',Current->input);
  315.         break;
  316.     case 256 + 73:    /* Page up */
  317.         putc('U',Current->input);
  318.         break;
  319.     case 256 + 79:    /* End */
  320.         putc('e',Current->input);
  321.         break;
  322.     case 256 + 80:    /* Cursor down */
  323.         putc('d',Current->input);
  324.         break;
  325.     case 256 + 81:    /* Page down */
  326.         putc('D',Current->input);
  327.         break;
  328.     }
  329.     fflush(Current->input);
  330.     return 0;
  331. }
  332.  
  333.